package controller;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import model.MonteCarloMulti;

public class MainMCMulti {
	
	private String CallPutFlag;
	private double S;
	private double X; 
	private double T; 
	private double r; 
	private double b; 
	private double v; 
	private int nSteps; 
	private int nSimulations;

	
	
	public MainMCMulti(ArrayList<String> listValeur) {
		super();
		this.CallPutFlag = listValeur.get(0);
		this.S = Double.parseDouble(listValeur.get(1));
		this.X = Double.parseDouble(listValeur.get(2));
		this.r = Double.parseDouble(listValeur.get(3));
		this.T = Double.parseDouble(listValeur.get(4));
		this.b = Double.parseDouble(listValeur.get(5));
		this.v = Double.parseDouble(listValeur.get(6));
		this.nSteps = Integer.parseInt(listValeur.get(7));
		this.nSimulations = Integer.parseInt(listValeur.get(8));
	}

	/**
	 * Methode qui controlle l appel de la fonction pour le multi thread
	 * @return double
	 * @throws InterruptedException
	 * @throws ExecutionException
	 */
	public double MCMulti() throws InterruptedException, ExecutionException {
		
		// On regarde ici le nombre de process sur l ordinateur
		final int numberOfCores = Runtime.getRuntime().availableProcessors();
	    final double blockingCoefficient = 0.1;
	    final int poolSize = (int)(numberOfCores / (1 - blockingCoefficient));
	    
	    System.out.println("Number of Cores available is " + numberOfCores);
	    System.out.println("Pool size is " + poolSize);
	    
	    // On cree une liste de future
	    final List<Future<Double>> valueOfStocks = new ArrayList<Future<Double>>();
	    final ExecutorService executorPool = Executors.newFixedThreadPool(poolSize); 
	    // On cree un callable
	    MonteCarloMulti cc =  new MonteCarloMulti(CallPutFlag, S, X, T, r, b, v, nSteps, nSimulations/poolSize);
	    
	    // On ajoute dans la liste le meme nombre de thread que l'on souhaite utiliser
	    for (int i=0; i<poolSize; i++)
	    {
	    	Future<Double> submit = executorPool.submit(cc);
	    	valueOfStocks.add(submit);
	    }
	    
	    
	    double sum = 0.0; 
	    // On calcule la somme
	    for(final Future<Double> valueOfAStock : valueOfStocks)  
	    	sum += valueOfAStock.get(); 
	    
	    executorPool.shutdown();
	    // On retourne la bonne valeur
		return sum / poolSize;
		
	}
}
